#include "nandflash.h"
 
//等待忙碌
void wait_idle()
{
	int i;
	/* NFSTAT[4]为1时表示可以操作NAND FLASH，为0是表示忙 */
	while(!(NFSTAT&(1<<4)));
	for(i=0; i<10; i++);
}
 
unsigned char read_nand_status()//芯片手册41 页
{
	unsigned char ret;
	int i;
 
	// 1. 发出片选信号
	nand_select_chip();
 
	// 2. 读状态
	write_cmd(0x70);
	for(i=0; i<10; i++);
	ret = read_data();
 
	// 3. 取消片选
	nand_deselect_chip();
	return ret;
}
 
void nand_select_chip()
{
	int i;
	NFCONT &= ~(1<<1);//210手册710页，NFCONT的[1]位
	/*NAND Flash Memory nRCS[0] signal control 
	0 = Force nRCS[0] to low (Enable chip select) 
	1 = Force nRCS[0] to High (Disable chip select) 
	Note: The setting all nCE[3:0] zero can not be allowed. Only 
	one nCE can be asserted to enable external NAND flash 
	memory. The lower bit has more priority when user set all 
	nCE[3:0] zeros. 
	除了[1]是和使能有关的，[22][23]也是，用来片选不同的NANDflash，0的时候使能，
	不能把这三个都设置为0.有多个设置为0的时候，相当于片选的是低位，这个操作片选了
	最低位
	*/
	for(i=0; i<10; i++);
}
 
void nand_deselect_chip()
{
	int i;
	NFCONT |= (1<<1);
    	//这是释放，芯片不被选择
	for(i=0; i<10; i++);
}
 
void write_cmd(int cmd)
{
	NFCMMD = cmd;//直接把命令写到这个NFCMMD寄存器就可以了，就是一些数
}
 
void write_addr(unsigned int addr)
{
    	//参考芯片手册9页，行列地址写入顺序，前两个是列，后三个是行int是个32位数,I/O口有8个，每次最多写8位
	NFADDR = (addr>>0) & 0xFF;/*A0--A7，写了8位*/
	wait_idle();
	NFADDR = (addr>>8) & 0x0F;/*A8--A11，这写了三位*/
	wait_idle();
	NFADDR = (addr>>12) & 0xFF;/*A12--A19,写入八位*/
	wait_idle();
	NFADDR = (addr>>20) & 0xFF;/*A20--A27,写入八位*/
	wait_idle();
	NFADDR = (addr>>28) & 0xFF;/*A28,写入1位*/
	wait_idle();//判断处理器忙不忙
}
unsigned char read_data()
{
	return NFDATA;//从这个地方直接取数据就可以了
	//这个寄存器是个32位的，在210的芯片手册695页，可以看到，数据存储格式是小端法，大于一个字节
	//数据返回时候，先返回的是低位
}
 
void write_data(unsigned char data)
{
	NFDATA = data;//同read_data，这里参数是unsigned char ，也可以为其他类型。
}
 
void nand_reset()//复位操作，NAND芯片手册42页，可以知道在写入0XFF命令后，R/B引脚会出现tRST时间长的低电平
{
    nand_select_chip();
    write_cmd(0xff);  // 复位命令
    wait_idle();//这一句前面严禁来说应该根据条件判断是否出现了低电平跳变到高电平
    nand_deselect_chip();
}
 
void nand_init()
{
	/*
	 * 设置时间参数(HCLK_PSYS = 667MHz/5 = 133MHz)
	 * NFCONF[15:12]: TACLS  = 2 	2/133Mhz  = 15ns > 12ns
	 * NFCONF[11:8]: TWRPH0 = 1 	15ns * 2 = 30ns  > 12ns
	 * NFCONF[7:4]: TWRPH1 = 1		15ns * 2 = 30ns  > 10ns
	 * NFCONF[1]: 当页大小为2KB或4KB时，1表示5分地址周期
	 */
	NFCONF |= (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4)|(1<<1);
 
	/*
	 * NFCONT[1]:为0时表示禁止片选，为1时表示使能片选
	 * NFCONT[0]:为0时表示禁止NAND FLASH控制器，反之使能
 	 */
	NFCONT |= (1<<1)|(1<<0);
 
	/* 设置相应管脚用于Nand Flash控制器*/
	MP0_1CON = 0x22333322;//210手册185页，这里面为3的原来是5，设置为3后为片选使能信号控制
	MP0_2CON = 0x00002222;
	MP0_3CON = 0x22222222;
 
	/* 复位NAND Flash */
	nand_reset();
 
	return;
}
 
/* 读ID */
void nand_read_id()
{
	nand_id_msg nand_id;
	/* 片选 */
	nand_select_chip();
 
	/* 发90命令 */
	write_cmd(0x90);//依据NAND芯片手册10页，读ID命令和31页时序图，确定写0x90命令和地址0x00
 
	/* 写00地址 */
	write_addr(0x00);
    //31页的图，在发送后的5个周期，分别返回5个数据，对应下面内容
	nand_id.maker_id  = read_data();//make code
	nand_id.device_id = read_data();//device code
	nand_id.id_3th    = read_data();//Internal Chip Number, Cell Type, Number of Simultaneously Programmed Pages, Etc
	nand_id.id_4th 	  = read_data();//Page Size, Block Size,Redundant Area Size, Organization, Serial Access Minimum
	nand_id.id_5th    = read_data();//Plane Number, Plane Size
	//具体的信息可以查看NAND芯片手册32页，有具体描述
	printf("\nmaker_id = %x,device_id = %x\r\n",nand_id.maker_id,nand_id.device_id);
	nand_deselect_chip();
}
/* 从NAND FLASH里读一页到buf指定的地址 */
int nand_read(unsigned int *buf, unsigned long start_addr, int size)
{
    //读取是以页为单位，具体时序在芯片手册35页，具体流程图在17页
	int i, j;
	/* 选中芯片 */
	nand_select_chip();
	 for(i=start_addr; i < (start_addr + size);)
	 {
		/* 发出READ0命令 */
		write_cmd(0x00);//参考芯片手册35页
		/* Write Address */
		write_addr(i);//5个周期，每个周期写一个，和芯片完全符合
		write_cmd(0x30);//参考芯片手册35页
		wait_idle();
		for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) 
		{
			*buf = read_data();
			buf++;
		}
	}
	if(read_nand_status()&0x01)//分析R/B判断是否完成
	/*The system controller can detect the completion of
this data transfer(tR) by analyzing the output of R/Bpin*/
	{
		/* 取消片选信号 */
		nand_deselect_chip();
		printf("\nNand read fail\r\n");
		return -1;
	}
	else
	{
		/* 取消片选信号 */
		nand_deselect_chip();
		printf("\nNand read success\r\n");
		return 0;
	}
}
/* 从buf指定的地址写一页数据到NAND FLASH */
int nand_write(unsigned char *sdram_addr, unsigned long nand_addr, unsigned long size)
{
    //和读类似，参考芯片手册25页 Page Program Operation
	int i, j;
	/* 选中芯片 */
	nand_select_chip();
 
	for(i=nand_addr; i < (nand_addr + size);)
	{
		/* 发出wirte0命令 */
		write_cmd(0x80);
 
		/* Write Address */
		write_addr(i);
		write_cmd(0x10);
		wait_idle();
 
		for(j=0; j < NAND_SECTOR_SIZE_LP&&size!=0; j++,size--,i++)
		{
			//delay(5);					//一定要有延时，否则会失败
			int k=0;
			for(k=0;k<5000;k++);
			write_data(*sdram_addr);
			sdram_addr++;
			nand_addr++;
		}
	}
 
	if(read_nand_status()&0x01)
	{
		/* 取消片选信号 */
		nand_deselect_chip();
		printf("\nNand write fail\r\n");
		return -1;
	}
	else
	{
		/* 取消片选信号 */
		nand_deselect_chip();
		printf("\nNand write success\r\n");
		return 0;
	}
}
unsigned char nand_erase(unsigned long block_num)
{
	unsigned long i = 0;
	// 获得row地址，即页地址r
	unsigned long row = block_num * NAND_BLOCK_SIZE;
	/*根据芯片手册的第9页的图，128k需要17个二进制位，所以那个应该是行地址，
	    2K，需要11位就可以了，所以这个是列地址，1block=64page，所以要用64*号码*/
	//1. 发出片选信号
	nand_select_chip();
	/* 2. 擦除：第一个周期发命令0x60，
		<span style="white-space:pre">	</span> *   第二个周期发块地址，
	 *   第三个周期发命令0xd0
	*/
	write_cmd(0x60);
	for(i=0; i<10; i++);
	// Row Address A12~A19，对比原来写入地址的5个环节，把row低8位取出后作为A12-A19
	NFADDR = row & 0xff;
	for(i=0; i<10; i++);
	// Row Address A20~A27
	NFADDR = (row >> 8) & 0xff;
	for(i=0; i<10; i++);
	// Row Address A28~A30
	NFADDR = (row >> 16) & 0xff;
	NFSTAT = (NFSTAT)|(1<<4);
	write_cmd(0xd0);
	for(i=0; i<10; i++);
	wait_idle();
	 
	 
	if(read_nand_status()&0x01)
	{
	    /* 取消片选信号 */
	    nand_deselect_chip();
	    printf("\nFail to erase block %d\r\n", block_num);
	    return -1;
	}
	else
	{
	    /* 取消片选信号 */
	    nand_deselect_chip();
	    printf("\nSuccess to erase block %d\r\n", block_num);
	    return 0;
	}
}
